import time

import ter
import iotUtils
class TBusModbusRtu( ter.TIotBus):
    def __init__(self , ter ):
        super().__init__(ter)
        self.client = None
    def init (self):
        try: 
            super().init()

        except Exception as er:
            print(er)
    def isConnected (self):
        res = False
        try:
            if self.client and self.client.isOpen():
                res = True
        except Exception as er:
            print(er)
        return res
    def start (self):
        try:
            comPort = self.busInfo['comPort']
            baudrate = self.busInfo['baudrate']
            parity = self.busInfo['parity']
            self.client = iotUtils.TIotUtils.getSerialClient( comPort , baudrate , parity)
            self.running = True

            taskList = list(self.tasks.values())
            taskIndex = -1

            #print('--- start modbus rtu------' , self.busInfo , len( taskList))
            while len(taskList)>0 and  self.running and self.isConnected():
                try:
                    nowTm = time.time()
                    taskIndex = taskIndex + 1
                    if taskIndex>= len(taskList):
                        taskIndex = 0
                    task = taskList[taskIndex]
                    taskLastTime = task['lastTm']
                    frequency = task['frequency']
                    flag = nowTm - taskLastTime > frequency
                    if flag :
                        task['lastTm'] = nowTm
                        registerBytes = None
                        unitId = task['unitId']
                        regAddr = task['regAddr']
                        regAddrH = regAddr>>8
                        regAddrL = regAddr % 256
                        regLen = task['regLen']
                        funCode = task['funCode']
                        sendList = [unitId, funCode, regAddrH, regAddrL, 0, regLen]
                        crc , crcH , crcL = iotUtils.TIotUtils.crc16(sendList)
                        sendList = sendList + [crcL , crcH]
                        sendBytes =bytearray(sendList)
                        self.client.flushInput()
                        self.client.flushOutput()
                        #print('task---', task['taskCode'], [hex(x) for x in sendBytes])
                        sendLen = self.client.write(sendBytes)
                        self.client.flush()
                        readHeadBytes = False
                        tm = time.time()
                        while not readHeadBytes:
                            try:
                                header = self.client.read(1)
                                if len(header)==1 and header[0]==unitId:
                                    readHeadBytes = True
                                    break
                                else:
                                    dlt = time.time() - tm
                                    if dlt>=2:
                                        break
                                    else:
                                        time.sleep(0.2)
                            except Exception as readErr:
                                print(readErr)
                                break
                        if readHeadBytes:
                            pgkSize = 2 + 2*regLen + 2
                            tm = time.time()
                            successFlag = False
                            while not successFlag:
                                successFlag = self.client.in_waiting>=pgkSize
                                if successFlag:
                                    break;
                                else:
                                    dlt = time.time() - tm
                                    if dlt>=5:
                                        break
                                    else:
                                        time.sleep(1)
                            if successFlag:
                                recBytes = self.client.read(pgkSize)
                                if recBytes[0] == funCode and recBytes[1] == regLen*2:
                                    registerBytes = list(recBytes)[2:-2]
                                    print(registerBytes)
                                    self.doOnTask(task , registerBytes)
                                recBytes = None
                            else:
                                print('modbus data fail.' , task)
                        else:
                            print('modbus header fail.' , task)
                except Exception as eer:
                    print(eer)
        except Exception as er:
            print(er)
    def stop (self):
        try:
            self.running = False
            if self.isConnected():
                self.client.close()
            self.client = None
        except Exception as er:
            print(er)

ter.iotTer.registBusType('modbusRtu' , TBusModbusRtu)